package com.atguigu.tingshu.user.service.impl;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.common.constant.KafkaConstant;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.service.KafkaService;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.user.UserPaidAlbum;
import com.atguigu.tingshu.model.user.UserPaidTrack;
import com.atguigu.tingshu.user.mapper.UserPaidAlbumMapper;
import com.atguigu.tingshu.user.mapper.UserPaidTrackMapper;
import com.google.common.collect.Maps;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.user.mapper.UserInfoMapper;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.swagger.v3.core.util.Json;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

	@Autowired
	private UserInfoMapper userInfoMapper;
	@Autowired
	private WxMaService wxMaService;
	@Autowired
	private RedisTemplate<String,String> redisTemplate;
	@Autowired
	private KafkaService kafkaService;
    @Autowired
    private UserPaidAlbumMapper userPaidAlbumMapper;
	@Autowired
	private UserPaidTrackMapper userPaidTrackMapper;

	@Override
	public String login(String code) {
		/**
		 * 登录逻辑：
		 * 1、请求微信服务器登录凭证校验接口校验临时凭证的合法性
		 * 2、如果校验没有抛出异常，就说明临时凭证合法，用户登录成功了，微信服务端会返回openId
		 * 3、如果校验抛出了异常，就说明临时凭证不合法，用户登录失败
		 * 4、使用openId从user_info表中查询用户数据
		 * 5、如果查询不到用户，表示用户第一次登录，注册用户
		 * 6、如果时新注册的用户，需要初始化用户的账号信息（向kafka中发送一条初始化用户账号信息的消息），
		 * service-account微服务需要从kafka中获取消息，初始化用户的账号数据
		 * 7、保存用户的登录状态：生成token，保存token数据到redis中，同时将token返回给前端
		 */
        try {
			//1、请求微信服务器登录凭证校验接口校验临时凭证的合法性
			//2、如果校验没有抛出异常，就说明临时凭证合法，用户登录成功了，微信服务端会返回openId
			//3、如果校验抛出了异常，就说明临时凭证不合法，用户登录失败
			WxMaJscode2SessionResult sessionResult = wxMaService.getUserService().getSessionInfo(code);
			String openid = sessionResult.getOpenid();
			//4、使用openId从user_info表中查询用户数据
			LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
			lambdaQueryWrapper.eq(UserInfo::getWxOpenId,openid);
			UserInfo userInfo = userInfoMapper.selectOne(lambdaQueryWrapper);
			//5、如果查询不到用户，表示用户第一次登录，注册用户
			if (userInfo==null){
				userInfo = new UserInfo();
				userInfo.setWxOpenId(openid);
				userInfo.setNickname("硅谷听友");
				userInfo.setAvatarUrl("https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
				userInfoMapper.insert(userInfo);
				//6、初始化用户的账号信息（向kafka中发送一条初始化用户账号信息的消息），
				//service-account微服务需要从kafka中获取消息，初始化用户的账号数据
				kafkaService.sendMsg(KafkaConstant.QUEUE_USER_REGISTER,String.valueOf(userInfo.getId()));
			}
			//7、保存用户的登录状态：生成token，保存token数据到redis中，同时将token返回给前端
			String token = UUID.randomUUID().toString().replaceAll("-", "");
			String userLoginRedisKey = RedisConstant.USER_LOGIN_KEY_PREFIX +token;
			redisTemplate.opsForValue().set(userLoginRedisKey, JSON.toJSONString(userInfo),RedisConstant.USER_LOGIN_KEY_TIMEOUT, TimeUnit.DAYS);
			return token;
		} catch (WxErrorException e) {
            e.printStackTrace();
			throw new GuiguException(ResultCodeEnum.DATA_ERROR);
        }
	}

	@Override
	public UserInfo getUserInfo() {
		Long userId = AuthContextHolder.getUserId();
		UserInfo userInfo = userInfoMapper.selectById(userId);
		return userInfo;
	}

	@Override
	public void updateUser(UserInfo userInfo) {
		Long userId = AuthContextHolder.getUserId();
		UserInfo dbuserInfo = userInfoMapper.selectById(userId);
		dbuserInfo.setAvatarUrl(userInfo.getAvatarUrl());
		dbuserInfo.setNickname(userInfo.getNickname());
		userInfoMapper.updateById(dbuserInfo);
	}

	@Override
	public Map<Long, Integer> userIsPaidTrack(Long albumId, List<Long> trackIds) {
		//创建一个Map对象，封装结果数据
		HashMap<Long, Integer> map = new HashMap<>();
		//判断用户是否购买过专辑
		Long userId = AuthContextHolder.getUserId();
		LambdaQueryWrapper<UserPaidAlbum> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		lambdaQueryWrapper.eq(UserPaidAlbum::getUserId,userId);
		lambdaQueryWrapper.eq(UserPaidAlbum::getAlbumId,albumId);
		UserPaidAlbum userPaidAlbum = userPaidAlbumMapper.selectOne(lambdaQueryWrapper);

		if (userPaidAlbum!=null){	//用户购买过专辑
			trackIds.forEach(trackId->{map.put(trackId,1);});
		}else {			//用户未购买专辑
			//判断传递过来的声音 用户是否购买过  select * from user_paid_track where user_id = ? and album_id = ? and track_id in (? , ? , ?)
			LambdaQueryWrapper<UserPaidTrack> userPaidTrackLambdaQueryWrapper = new LambdaQueryWrapper<>() ;
			userPaidTrackLambdaQueryWrapper.eq(UserPaidTrack::getUserId,userId) ;
			userPaidTrackLambdaQueryWrapper.eq(UserPaidTrack::getAlbumId , albumId) ;
			userPaidTrackLambdaQueryWrapper.in(UserPaidTrack::getTrackId , trackIds) ;
			List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(userPaidTrackLambdaQueryWrapper);

			if(CollectionUtils.isEmpty(userPaidTrackList)) {		//用户没购买声音
				trackIds.forEach(trackId -> {
					map.put(trackId , 0) ;
				});
			}else {

				List<Long> paidTrackIds = userPaidTrackList.stream().map(userPaidTrack -> userPaidTrack.getTrackId()).collect(Collectors.toList());
				trackIds.forEach(trackId -> {
					if(paidTrackIds.contains(trackId)) {		//声音id包含用户购买的声音
						map.put(trackId , 1) ;
					}else {
						map.put(trackId , 0) ;
					}
				});
			}
		}
		return map;
	}
}
